home *** CD-ROM | disk | FTP | other *** search
- ///-*-C++-*-//////////////////////////////////////////////////////////////////
- //
- // Hoard: A Fast, Scalable, and Memory-Efficient Allocator
- // for Shared-Memory Multiprocessors
- // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery
- //
- // Copyright (c) 1998-2000, The University of Texas at Austin.
- //
- // This library is free software; you can redistribute it and/or modify
- // it under the terms of the GNU Library General Public License as
- // published by the Free Software Foundation, http://www.fsf.org.
- //
- // This library is distributed in the hope that it will be useful, but
- // WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Library General Public License for more details.
- //
- //////////////////////////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////////////////////////
- //
- // Note: This file was modified by Crystal Decisions in June 2002.
- //
- //////////////////////////////////////////////////////////////////////////////
-
- #include "config.h"
-
- #include "heap.h"
- #include "processheap.h"
- #include "superblock.h"
-
- static const char version[] = "The Hoard memory allocator, version 2.0 (http://www.hoard.org). Copyright (C) 1998, 1999, 2000 The University of Texas at Austin. $Id: heap.cpp,v 1.68 2000/03/27 21:55:26 emery Exp $";
-
- // NB: Use maketable.cpp to update this
- // if SIZE_CLASSES, ALIGNMENT, SIZE_CLASS_BASE, MAX_EMPTY_SUPERBLOCKS,
- // or SUPERBLOCK_SIZE changes.
-
- #ifdef WIN32
- // The CRPE does a lot of 63KB buffer allocations. So, one of the sizeclasses is modified from 56352UL to 65280UL.
- // The size class immediately before 64KB is 65280 (reserve 256 bytes for superblock and memory block header)
- size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {8UL, 16UL, 24UL, 32UL, 40UL, 48UL, 56UL, 72UL, 80UL, 96UL, 120UL, 144UL, 168UL, 200UL, 240UL, 288UL, 344UL, 416UL, 496UL, 592UL, 712UL, 856UL, 1024UL, 1232UL, 1472UL, 1768UL, 2120UL, 2544UL, 3048UL, 3664UL, 4392UL, 5272UL, 6320UL, 7584UL, 9104UL, 10928UL, 13112UL, 15728UL, 18872UL, 22648UL, 27176UL, 32616UL, 39136UL, 46960UL, 65280UL, 67624UL, 81144UL, 97376UL, 116848UL, 140216UL, 168256UL, 201904UL, 242288UL, 290744UL, 348896UL, 418672UL, 502408UL, 602888UL, 723464UL, 868152UL, 1041784UL, 1250136UL, 1500160UL, 1800192UL, 2160232UL, 2592280UL, 3110736UL, 3732880UL, 4479456UL, 5375344UL, 6450408UL, 7740496UL, 9288592UL, 11146312UL, 13375568UL, 16050680UL, 19260816UL, 23112984UL, 27735576UL, 33282688UL, 39939224UL, 47927072UL, 57512488UL, 69014984UL, 82817976UL, 99381576UL, 119257888UL, 143109472UL, 171731360UL, 206077632UL, 247293152UL, 296751776UL, 356102144UL, 427322560UL, 512787072UL, 615344512UL, 738413376UL, 886096064UL, 1063315264UL};
- #else
- size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {8UL, 16UL, 24UL, 32UL, 40UL, 48UL, 56UL, 72UL, 80UL, 96UL, 120UL, 144UL, 168UL, 200UL, 240UL, 288UL, 344UL, 416UL, 496UL, 592UL, 712UL, 856UL, 1024UL, 1232UL, 1472UL, 1768UL, 2120UL, 2544UL, 3048UL, 3664UL, 4392UL, 5272UL, 6320UL, 7584UL, 9104UL, 10928UL, 13112UL, 15728UL, 18872UL, 22648UL, 27176UL, 32616UL, 39136UL, 46960UL, 56352UL, 67624UL, 81144UL, 97376UL, 116848UL, 140216UL, 168256UL, 201904UL, 242288UL, 290744UL, 348896UL, 418672UL, 502408UL, 602888UL, 723464UL, 868152UL, 1041784UL, 1250136UL, 1500160UL, 1800192UL, 2160232UL, 2592280UL, 3110736UL, 3732880UL, 4479456UL, 5375344UL, 6450408UL, 7740496UL, 9288592UL, 11146312UL, 13375568UL, 16050680UL, 19260816UL, 23112984UL, 27735576UL, 33282688UL, 39939224UL, 47927072UL, 57512488UL, 69014984UL, 82817976UL, 99381576UL, 119257888UL, 143109472UL, 171731360UL, 206077632UL, 247293152UL, 296751776UL, 356102144UL, 427322560UL, 512787072UL, 615344512UL, 738413376UL, 886096064UL, 1063315264UL};
- #endif
-
-
- #ifndef CRYSTAL_HOARD
-
- size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {4096UL, 2048UL, 1364UL, 1024UL, 816UL, 680UL, 584UL, 452UL, 408UL, 340UL, 272UL, 224UL, 192UL, 160UL, 136UL, 112UL, 92UL, 76UL, 64UL, 52UL, 44UL, 36UL, 32UL, 24UL, 20UL, 16UL, 12UL, 12UL, 8UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL};
-
- #else // CRYSTAL_HOARD
-
- #ifdef WIN32
- size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {32768UL, 16384UL, 10920UL, 8192UL, 6552UL, 5460UL, 4680UL, 3640UL, 3276UL, 2728UL, 2184UL, 1820UL, 1560UL, 1308UL, 1092UL, 908UL, 760UL, 628UL, 528UL, 440UL, 368UL, 304UL, 256UL, 212UL, 176UL, 148UL, 120UL, 100UL, 84UL, 68UL, 56UL, 48UL, 40UL, 32UL, 28UL, 20UL, 16UL, 16UL, 12UL, 8UL, 8UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL};
- #else
- size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {4096UL, 2048UL, 1364UL, 1024UL, 816UL, 680UL, 584UL, 452UL, 408UL, 340UL, 272UL, 224UL, 192UL, 160UL, 136UL, 112UL, 92UL, 76UL, 64UL, 52UL, 44UL, 36UL, 32UL, 24UL, 20UL, 16UL, 12UL, 12UL, 8UL, 8UL, 56UL, 48UL, 40UL, 32UL, 28UL, 20UL, 16UL, 16UL, 12UL, 8UL, 8UL, 8UL, 24UL, 20UL, 16UL, 12UL, 12UL, 8UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL};
- #endif // WIN32
-
- // NB: If you change these values, you will also need to change maketable.cpp, and recalculate the
- // threshold table above.
-
- // Note: I just made these numbers up. Maybe other numbers would make more sense.
-
- #ifdef WIN32
- size_t hoardHeap::_superblockSize[hoardHeap::SUPERBLOCK_CLASSES] = { 65536UL };
- int hoardHeap::_reusableSuperblockLimit[hoardHeap::SUPERBLOCK_CLASSES] = { 32 };
- #else
- size_t hoardHeap::_superblockSize[hoardHeap::SUPERBLOCK_CLASSES] = { 8192UL, 65536UL, 262144UL };
- int hoardHeap::_reusableSuperblockLimit[hoardHeap::SUPERBLOCK_CLASSES] = { 128, 32, 16 };
- #endif
-
- #endif // CRYSTAL_HOARD
-
-
- hoardHeap::hoardHeap (void)
- : _index (0)
- #ifndef CRYSTAL_HOARD
- ,_reusableSuperblocks (NULL),
- _reusableSuperblocksCount (0)
- #endif
- #if HEAP_DEBUG
- , _magic (HEAP_MAGIC)
- #endif
- {
- // Initialize the per-heap lock.
- hoardLockInit (_lock);
- for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
- for (int j = 0; j < SIZE_CLASSES; j++) {
- // Initialize all superblocks lists to empty.
- _superblocks[i][j] = NULL;
- }
- }
- for (int k = 0; k < SIZE_CLASSES; k++) {
- _leastEmptyBin[k] = 0;
- }
- #ifdef CRYSTAL_HOARD
- // Initialize the list of reusable superblocks
- for ( int m = 0; m < SUPERBLOCK_CLASSES; m++)
- {
- _reusableSuperblocks[m] = NULL;
- _reusableSuperblocksCount[m] = 0;
- }
- #endif
- }
-
-
- void hoardHeap::insertSuperblock (int sizeclass,
- superblock * sb,
- processHeap * pHeap)
- {
- assert (sb->isValid());
- assert (sb->getBlockSizeClass() == sizeclass);
- assert (sb->getPrev() == NULL);
- assert (sb->getNext() == NULL);
- assert (_magic == HEAP_MAGIC);
-
- // Now it's ours.
- sb->setOwner (this);
-
- // How full is this superblock? We'll use this information to put
- // it into the right 'bin'.
- sb->computeFullness();
- int fullness = sb->getFullness();
-
- // Update the stats.
- incStats (sizeclass,
- sb->getNumBlocks() - sb->getNumAvailable(),
- sb->getNumBlocks());
-
- if ((fullness == 0) &&
- (sb->getNumBlocks() > 1) &&
- (sb->getNumBlocks() == sb->getNumAvailable()))
- {
- // Recycle this superblock.
- recycle (sb);
- } else {
-
- // Insert it into the appropriate list.
- superblock *& head = _superblocks[fullness][sizeclass];
- sb->insertBefore (head);
- head = sb;
- assert (head->isValid());
-
- // Reset the least-empty bin counter.
- _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
- }
- }
-
-
- superblock * hoardHeap::removeMaxSuperblock (int sizeclass)
- {
- assert (_magic == HEAP_MAGIC);
-
- superblock * head = NULL;
-
- // First check the reusable superblocks list.
-
- head = reuse (sizeclass);
- if (head) {
- // We found one. Since we're removing this superblock, update the
- // stats accordingly.
- decStats (sizeclass,
- head->getNumBlocks() - head->getNumAvailable(),
- head->getNumBlocks());
-
- return head;
- }
-
- // Instead of finding the superblock with the most available space
- // (something that would either involve a linear scan through the
- // superblocks or maintaining the superblocks in sorted order), we
- // just pick one that is no more than
- // 1/(SUPERBLOCK_FULLNESS_GROUP-1) more full than the superblock
- // with the most available space. We start with the emptiest group.
-
- int i = 0;
-
- // Note: the last group (SUPERBLOCK_FULLNESS_GROUP - 1) is full, so
- // we never need to check it. But for robustness, we leave it in.
- while (i < SUPERBLOCK_FULLNESS_GROUP) {
- head = _superblocks[i][sizeclass];
- if (head) {
- break;
- }
- i++;
- }
-
- if (!head) {
- return NULL;
- }
-
- // Make sure that this superblock is at least 1/EMPTY_FRACTION
- // empty.
- assert (head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
-
- removeSuperblock (head, sizeclass);
-
- assert (head->isValid());
- assert (head->getPrev() == NULL);
- assert (head->getNext() == NULL);
- return head;
- }
-
-
- void hoardHeap::removeSuperblock (superblock * sb,
- int sizeclass)
- {
- assert (_magic == HEAP_MAGIC);
-
- assert (sb->isValid());
- assert (sb->getOwner() == this);
- assert (sb->getBlockSizeClass() == sizeclass);
-
- for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
- if (sb == _superblocks[i][sizeclass]) {
- _superblocks[i][sizeclass] = sb->getNext();
- if (_superblocks[i][sizeclass] != NULL) {
- assert (_superblocks[i][sizeclass]->isValid());
- }
- break;
- }
- }
-
- sb->remove();
- decStats (sizeclass, sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
- }
-
-
- void hoardHeap::moveSuperblock (superblock * sb,
- int sizeclass,
- int fromBin,
- int toBin)
- {
- assert (_magic == HEAP_MAGIC);
- assert (sb->isValid());
- assert (sb->getOwner() == this);
- assert (sb->getBlockSizeClass() == sizeclass);
- assert (sb->getFullness() == toBin);
-
- // Remove the superblock from the old bin.
-
- superblock *& oldHead = _superblocks[fromBin][sizeclass];
- if (sb == oldHead) {
- oldHead = sb->getNext();
- if (oldHead != NULL) {
- assert (oldHead->isValid());
- }
- }
-
- sb->remove();
-
- // Insert the superblock into the new bin.
-
- superblock *& newHead = _superblocks[toBin][sizeclass];
- sb->insertBefore (newHead);
- newHead = sb;
- assert (newHead->isValid());
-
- // Reset the least-empty bin counter.
- _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
- }
-
-
- #ifdef CRYSTAL_HOARD
- bool hoardHeap::unsbrkIfLimit(processHeap * pHeap, superblock * sb)
- {
- assert(sb!=NULL);
- assert(pHeap!=NULL);
-
- // If we've reached our limit of reusable superblocks, then free this
- // block immediately.
- int sbClass = sb->getSuperblockClass();
- if ( _reusableSuperblocksCount[sbClass] >= _reusableSuperblockLimit[sbClass] )
- {
- #if HEAP_LOG
- // Record the memory deallocation.
- MemoryRequest m;
- m.deallocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
- pHeap->getLog(getIndex()).append(m);
- #endif
- #if HEAP_FRAG_STATS
- pHeap->setDeallocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
- #endif
- const size_t superblockSize = superblockSizeFromClass(sbClass);
- hoardUnsbrk (sb, superblockSize);
- return true;
- }
-
- return false;
- }
- #endif
-
- // The heap lock must be held when this procedure is called.
-
- int hoardHeap::freeBlock (block *& b,
- superblock *& sb,
- int sizeclass,
- processHeap * pHeap)
- {
- assert (sb->isValid());
- assert (b->isValid());
- assert (this == sb->getOwner());
-
- const int oldFullness = sb->getFullness();
- sb->putBlock (b);
- decUStats (sizeclass);
- const int newFullness = sb->getFullness();
-
- // Free big superblocks.
- if (sb->getNumBlocks() == 1) {
- removeSuperblock (sb, sizeclass);
- const size_t s = sizeFromClass (sizeclass);
- const int blksize = align (sizeof(block) + s);
- #if HEAP_LOG
- // Record the memory deallocation.
- MemoryRequest m;
- m.deallocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
- pHeap->getLog(getIndex()).append(m);
- #endif
- #if HEAP_FRAG_STATS
- pHeap->setDeallocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
- #endif
- hoardUnsbrk (sb, align (sizeof(superblock) + blksize));
- return 1;
- }
-
- // If the fullness value has changed, move the superblock.
- if (newFullness != oldFullness) {
- moveSuperblock (sb, sizeclass, oldFullness, newFullness);
- } else {
- // Move the superblock to the front of its list (to reduce
- // paging).
- superblock *& head = _superblocks[newFullness][sizeclass];
- if (sb != head) {
- sb->remove();
- sb->insertBefore (head);
- head = sb;
- }
- }
-
- // If the superblock is now empty, recycle it.
-
- if ((newFullness == 0) &&
- (sb->getNumBlocks() == sb->getNumAvailable()))
- {
- removeSuperblock (sb, sizeclass);
- #ifdef CRYSTAL_HOARD
- if (this == (hoardHeap *) pHeap) {
- if (unsbrkIfLimit(pHeap,sb))
- return 1;
- }
- #endif // CRYSTAL_HOARD
- recycle (sb);
- // Update the stats. This restores the stats to their state
- // before the call to removeSuperblock, above.
- incStats (sizeclass,
- sb->getNumBlocks() - sb->getNumAvailable(),
- sb->getNumBlocks());
- }
-
-
- // If this is the process heap, then we're done.
- if (this == (hoardHeap *) pHeap) {
- return 0;
- }
-
- //
- // Release a superblock, if necessary.
- //
-
- //
- // Check to see if the amount free exceeds the release threshold
- // (two superblocks worth of blocks for a given sizeclass) and if
- // the heap is sufficiently empty.
- //
-
- int inUse, allocated;
- getStats (sizeclass, inUse, allocated);
-
- // printf ("inUse: %d, empty threshold: (%d; %d), allocated: %d\n", inUse, (allocated - allocated / EMPTY_FRACTION), allocated - getReleaseThreshold(sizeclass), allocated);
-
- if ((inUse < allocated - getReleaseThreshold(sizeclass))
- && (EMPTY_FRACTION * inUse < EMPTY_FRACTION * allocated - allocated)) {
-
- // We've crossed the magical threshold. Find the superblock with
- // the most free blocks and give it to the process heap.
- superblock * const maxSb = removeMaxSuperblock (sizeclass);
- assert (maxSb != NULL);
-
- // Update the statistics.
-
- assert (maxSb->getNumBlocks() >= maxSb->getNumAvailable());
-
- #ifdef CRYSTAL_HOARD
- // return 1 => don't unUpLock sb in the caller, if it was unsbrked
- // inside release
- if(pHeap->release (maxSb) && sb==maxSb) {
- return 1;
- }
- #else
- pHeap->release (maxSb);
- #endif
- }
- return 0;
- }
-